package org.je.refl;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
 * @author fanyifeng 2012-8-30 下午3:16:27
 */
public class ClassUtil
{
	private static Map<String, Class<?>>	specialClassMap	= new HashMap<String, Class<?>>();

	static {
		specialClassMap.put("boolean" ,boolean.class);// 1
		specialClassMap.put("byte" ,byte.class);// 2
		specialClassMap.put("char" ,char.class);// 3
		specialClassMap.put("short" ,short.class);// 4
		specialClassMap.put("int" ,int.class);// 5
		specialClassMap.put("long" ,long.class);// 6
		specialClassMap.put("float" ,float.class);// 7
		specialClassMap.put("double" ,double.class);// 8

		specialClassMap.put("str" ,String.class);
		specialClassMap.put("string" ,String.class);
		specialClassMap.put("date" ,Date.class);

		specialClassMap.put("Boolean" ,Boolean.class);// 1
		specialClassMap.put("Byte" ,Byte.class);// 2
		specialClassMap.put("Char" ,Character.class);// 3
		specialClassMap.put("Short" ,Short.class);// 4
		specialClassMap.put("Int" ,Integer.class);// 5
		specialClassMap.put("Long" ,Long.class);// 6
		specialClassMap.put("Float" ,Float.class);// 7
		specialClassMap.put("Double" ,Double.class);// 8
		
		specialClassMap.put("list" ,ArrayList.class);// 8
		specialClassMap.put("map" ,HashMap.class);// 8
		specialClassMap.put("set" ,HashSet.class);// 8
	}

	/**
	 * @param cl
	 * @return bool
	 */
	public static boolean isAbstract(Class<?> cl) {
		return cl.isPrimitive() == false && Modifier.isAbstract(cl.getModifiers());
	}

	/**
	 * @param classLoader
	 */
	public static void setConcurrentClassLoader(ClassLoader classLoader) {
		if (classLoader == null)
			throw new NullPointerException("classLoader-is-null");
		Thread.currentThread().setContextClassLoader(classLoader);
	}

	/**
	 * @param name
	 * @return Class
	 */
	public static Class<?> getClassByName(String name) {
		if (name == null)
			throw new NullPointerException("className-is-null");
		Class<?> cl = specialClassMap.get(name);
		if (cl != null)
			return cl;

		try {
			return Thread.currentThread().getContextClassLoader().loadClass(name);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException("class-not-found:" + name);
		}
	}

	/**
	 * @param cl
	 * @return Obj
	 */
	public static Object createObject(Class<?> cl) {
		if (cl == null)
			throw new NullPointerException("cl-is-null");
		if (isAbstract(cl))
			throw new RuntimeException("abstract-class:" + cl.getName());
		if (cl == Object.class) {
			return new Object();
		}
		Object obj = PrimaryClassUtil.createObject(cl);
		if (obj != null)
			return obj;
		obj = SpecialClassUtil.createObject(cl);
		if (obj != null)
			return obj;
		return createComplexObject(cl);
	}

	/**
	 * 
	 * @param cl
	 * @param val
	 * @return obj
	 */
	public static Object createObject(Class<?> cl, String val) {
		if (cl == null)
			throw new NullPointerException("cl-is-null");
		if (isAbstract(cl))
			throw new RuntimeException("abstract-class:" + cl.getName());
		if (cl == Object.class) {
			if (val != null)
				throw new RuntimeException("construct-error, class=Object.class,value=" + val);
			return new Object();
		}
		Object obj = PrimaryClassUtil.createObject(cl ,val);
		if (obj != null)
			return obj;
		obj = SpecialClassUtil.createObject(cl ,val);
		if (obj != null)
			return obj;
		return createComplexObject(cl ,val);
	}

	/**
	 * @param className
	 * @return obj
	 */
	public static Object createObject(String className) {
		return createObject(getClassByName(className));
	}

	/**
	 * @param className
	 * @param value
	 * @return obj
	 */
	public static Object createObject(String className, String value) {
		return createObject(getClassByName(className) ,value);
	}

	private static Object createComplexObject(Class<?> cl) {
		try {
			return cl.newInstance();
		} catch (Exception ex) {}

		try {
			Constructor<?> con = cl.getDeclaredConstructor();
			con.setAccessible(true);
			return con.newInstance();
		} catch (Exception e) {
			throw new RuntimeException("construct-error:" + cl.getName() + ", " + e.getMessage());
		}
	}

	private static Object createComplexObject(Class<?> cl, String val) {
		try {
			Constructor<?> con = cl.getDeclaredConstructor(String.class);
			con.setAccessible(true);
			return con.newInstance(val);
		} catch (Exception e) {
			throw new RuntimeException("construct-error:" + cl.getName() + ", " + e.getMessage());
		}
	}
}
